﻿using System;
using System.Linq.Expressions;

namespace TelerikMvcGridCustomBindingHelper.Util
{
    public class ParameterToMemberExpressionRebinder : ExpressionVisitor
    {
        readonly ParameterExpression _paramExpr;
        readonly MemberExpression _memberExpr;

        ParameterToMemberExpressionRebinder(ParameterExpression paramExpr, MemberExpression memberExpr)
        {
            _paramExpr = paramExpr;
            _memberExpr = memberExpr;
        }

        public override Expression Visit(Expression p)
        {
            return base.Visit(p == _paramExpr ? _memberExpr : p);
        }

        public static Expression<Func<TRoot, TResult>> CombinePropertySelectorWithPredicate<TRoot, /*TSubMember,*/ TResult>(
            //Expression<Func<TRoot, TSubMember>> propertySelector,
            LambdaExpression propertySelector,
            //Expression<Func<TSubMember, TResult>> propertyPredicate
            LambdaExpression propertyPredicate)
        {
            var memberExpression = propertySelector == null ? null : propertySelector.Body as MemberExpression;

            if (memberExpression == null)
            {
                throw new NotSupportedException(string.Format("The expression is not supported, because it must have a bory with a MemberExpression: {0}", (propertySelector == null ? "null" : propertySelector.ToString())));
            }

            var expr = Expression.Lambda<Func<TRoot, TResult>>(propertyPredicate.Body, propertySelector.Parameters);
            var rebinder = new ParameterToMemberExpressionRebinder(propertyPredicate.Parameters[0], memberExpression);
            expr = (Expression<Func<TRoot, TResult>>)rebinder.Visit(expr);

            return expr;
        }
    }
}